home *** CD-ROM | disk | FTP | other *** search
/ Chip: 2005 Utilities / CHIP Utilities 2005 / CHIP Utilities 2005.iso / dosapps / pci / pci.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2004-07-08  |  57.7 KB  |  2,195 lines

  1. Program PCI;
  2.  
  3. {$G+}
  4. {$R+}
  5. {$S-}
  6. {$I+}
  7. {$N+}
  8. {$E+}
  9. {$Q-}
  10.  
  11.  
  12.  
  13. uses newdelay,dos,crt;
  14.  
  15.  
  16. {$I classes.pas}
  17.  
  18.  
  19. {
  20.   This code is Written by Craig Hart in 1996-2004. It is released as freeware;
  21.   please use and modify at will. No gurarantees are made or implied.
  22.  
  23.  
  24.   Please read the accompaning documentation PCI.DOC for all the info
  25.   relating to this program!
  26. }
  27.  
  28.  
  29.  
  30. const
  31.   revision    : string[5]='0.49ß';
  32.  
  33. var
  34.   agpbusnum,
  35.   lw,
  36.   wrlncount,
  37.   PCIverhi,
  38.   PCIverlo,
  39.   PCIchar,
  40.   PCI_hibus,
  41.   errcode,
  42.   deviceid,
  43.   func,
  44.   info,
  45.   lb,
  46.   bus,
  47.   sum,
  48.   disp,
  49.   cap_ptr    : byte;
  50.  
  51.   found,
  52.   businfo,
  53.   tableok,
  54.   dorouting,
  55.   dopcirouting,
  56.   userev,
  57.   summary,
  58.   bogusid,
  59.   genssid,
  60.   dumpregs,
  61.   usebios,
  62.   failed,
  63.   first,
  64.   installermode    : boolean;
  65.  
  66.  
  67.   irqmap    : array[0..15] of byte;
  68.  
  69.  
  70.   romsize,
  71.   romresult    : longint;
  72.  
  73.   spl        : real;
  74.  
  75.   mb,
  76.   ml,
  77.   conmap,
  78.   len,
  79.   addr,
  80.   index,
  81.   i,
  82.   j,
  83.   l,
  84.   v        : word;
  85.  
  86.   f        : text;
  87.  
  88.   revchk,
  89.   oemidnum,
  90.   oemidstr,
  91.   cmdstr,
  92.   vstr,
  93.   cmpstr    : string;
  94.  
  95.  
  96.   infotbl    : array[0..$ff] of byte;
  97.  
  98.   irqbuff    : array[0..1023] of byte;
  99.  
  100.   linecounter   : word;
  101.   org_output    : pointer;
  102.  
  103.  
  104.   cardbus    : array[1..16] of byte;
  105.   cbu,
  106.   cardptr    : byte;
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124. procedure pagefilter1(var t:text);assembler;
  125. asm
  126.   push ax
  127.   push di
  128.   push es
  129.   push cx
  130.  
  131.   les di,[t]
  132.   mov cx,es:[di+TextRec.BufPos]
  133.   les di,es:[di+TextRec.BufPtr]
  134.   cld
  135.   mov al,10
  136.  
  137. @sl:
  138.   jcxz @ret
  139.   dec cx
  140.   scasb
  141.   jne @sl
  142.   inc linecounter
  143.   jmp @sl
  144.  
  145. @ret:
  146.   pop cx
  147.   pop es
  148.   pop di
  149.   pop ax
  150. end;
  151.  
  152. procedure pagefilter2;assembler;
  153. asm
  154.   push ax
  155.   mov ax,WindMax
  156.   shr ax,8
  157.   cmp linecounter,ax
  158.   jb @ret
  159.  
  160.   sub ax,ax
  161.   int $16
  162.  
  163.   mov linecounter,0
  164.  
  165. @ret:
  166.   pop ax
  167. end;
  168.  
  169. procedure page_output_FlushFunc;assembler;
  170. asm
  171.   push es
  172.   push bx
  173.   call pagefilter1
  174.   push es
  175.   push bx
  176.   call [org_output]
  177.   call pagefilter2
  178.   retf 4
  179. end;
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191. function cvtb(b:byte) : byte;
  192. begin
  193.   if b>9 then cvtb:=b+ord('A')-10 else cvtb:=b+ord('0');
  194. end;
  195.  
  196. function wrhexb(byt:byte): string;
  197. begin
  198.  wrhexb:=chr(cvtb(byt and $0f));
  199. end;
  200.  
  201. function wrhex(byt:byte) : string;
  202. begin
  203.   wrhex:=chr(cvtb((byt and $f0) shr 4))+chr(cvtb(byt and $0f));
  204. end;
  205.  
  206. function wrhexw(wor:word): string;
  207. begin
  208.   wrhexw:=chr(cvtb(wor shr 12))+chr(cvtb((wor shr 8) and $f))+chr(cvtb((wor shr 4) and $f))+chr(cvtb(wor and $f));
  209. end;
  210.  
  211.  
  212. (* Make the PCI configuration status register printout pretty *)
  213. (* Input = the string to be output *)
  214.  
  215. Procedure printstatus (s : string);
  216. Begin
  217.   if not first then if (length(s)+wherex)>78 then
  218.   begin
  219.     writeln(',');
  220.     write('   ');
  221.   end else write(', ');
  222.   write(s);
  223.   first:=false;
  224. End;
  225.  
  226.  
  227. function IORedirected : boolean ; Assembler;
  228. asm
  229.   push ds
  230.   mov ax,prefixseg
  231.   mov ds,ax
  232.   xor bx,bx
  233.   les bx,[bx + $34]
  234.   mov al,es:[bx]
  235.   mov ah,es:[bx +1]
  236.   pop ds
  237.   cmp al,ah
  238.   mov al,true
  239.   jne @exit
  240.  
  241.   mov al,false
  242.  
  243.  @exit:
  244. end;
  245.  
  246. function lookup_bios(deviceid,func,bus:byte;index:word) : byte;
  247.  
  248. var inf:byte;
  249.  
  250. begin
  251.   asm
  252.     mov ax,$b108
  253.     mov bl,deviceid
  254.     shl bl,3
  255.     add bl,func
  256.     mov bh,bus
  257.     mov di,index
  258.     int $1a
  259.     jc @exit
  260.  
  261.     mov failed,false
  262.     mov inf,cl
  263.   @exit:
  264.     mov errcode,ah
  265.   end;
  266.   lookup_bios:=inf;
  267. end;
  268.  
  269.  
  270. function lookup_hw(deviceid,func,bus:byte;index:word) : byte;
  271. var inf:byte;
  272.  
  273. begin
  274.   asm
  275.     mov ax,$8000
  276.     mov al,bus
  277.     db $66;shl ax,16
  278.  
  279.     mov ax,index
  280.     and ax,00fch
  281.     mov ah,deviceid
  282.     shl ah,3
  283.     add ah,func
  284.  
  285.     mov dx,0cf8h
  286.     db $66;out dx,ax
  287.  
  288.     mov ax,index
  289.     and ax,3
  290.     mov bl,8
  291.     mul bl
  292.     mov cx,ax
  293.  
  294.     mov dx,0cfch
  295.     db $66;in ax,dx
  296.     db $66;shr ax,cl
  297.     mov inf,al
  298.     mov failed,false
  299.  
  300.  
  301.     db $66;xor ax,ax
  302.     mov dx,0cf8h
  303.     db $66;out dx,ax
  304.  
  305.   end;
  306.   lookup_hw:=inf;
  307. end;
  308.  
  309.  
  310. procedure write_dword_bios(deviceid,func,bus:byte;index,datah,datal:word); assembler;
  311. asm
  312.     mov ax,$b10d
  313.     mov bl,deviceid
  314.     shl bl,3
  315.     add bl,func
  316.     mov bh,bus
  317.     mov di,index
  318.     mov cx,datah
  319.     db $66; rol cx,16
  320.     mov cx,datal
  321.     int $1a
  322.     mov errcode,ah
  323. end;
  324.  
  325. procedure write_dword_hw(deviceid,func,bus:byte;index,datah,datal:word); assembler;
  326. asm
  327.     mov ax,$8000
  328.     mov al,bus
  329.     db $66;shl ax,16
  330.  
  331.     mov ax,index
  332.     and ax,00fch
  333.     mov ah,deviceid
  334.     shl ah,3
  335.     add ah,func
  336.  
  337.     mov dx,0cf8h
  338.     db $66;out dx,ax
  339.  
  340.     mov ax,index
  341.     and ax,3
  342.     mov bl,8
  343.     mul bl
  344.     mov cx,ax
  345.  
  346.  
  347.     mov ax,datah
  348.     db $66;shl ax,16
  349.     mov ax,datal
  350.  
  351.     mov dx,0cfch
  352.     db $66;out dx,ax
  353.     mov failed,false
  354.  
  355.  
  356.     db $66;xor ax,ax
  357.     mov dx,0cf8h
  358.     db $66;out dx,ax
  359.  
  360. end;
  361.  
  362. procedure listmap(va:word;dispst:string);
  363. var
  364.   comma     : byte;
  365.   failed : boolean;
  366.   l,
  367.   j     : word;
  368.  
  369. begin
  370.   failed:=true;
  371.   write(dispst);
  372.   comma:=0;
  373.   for l:=0 to 15 do if (va and (1 shl l))>0 then inc(comma);
  374.  
  375.   l:=1;
  376.   j:=0;
  377.   repeat
  378.     if (va and l)=l then
  379.     begin
  380.       write(j);
  381.       if comma>1 then write(',') else write(' ');
  382.       dec(comma);
  383.       failed:=false;
  384.     end;
  385.     l:=l shl 1;
  386.     inc(j);
  387.   until j=16;
  388.   if failed then writeln('None') else writeln;
  389. end;
  390.  
  391.  
  392. procedure lookupven(silent:boolean);
  393. begin
  394.   reset(f);
  395.   failed:=true;
  396.   repeat
  397.     readln(f,vstr);
  398.     if length(vstr)<3 then vstr:=';   oops';
  399.     if (vstr[1]='V') and (copy(vstr,3,4)=cmpstr) then
  400.     begin
  401.       textcolor(14);
  402.       if not silent then write(copy(vstr,8,length(vstr)));
  403.       textcolor(7);
  404.       failed:=false;
  405.     end;
  406.   until eof(f) or not failed;
  407.   if failed then
  408.   begin
  409.     textcolor(12);
  410.     if not silent then write('Unknown');
  411.     textcolor(7);
  412.   end;
  413. end;
  414.  
  415. procedure lookupdev;
  416. begin
  417.   failed:=true;
  418.   if not eof(f) then
  419.   begin
  420.     repeat
  421.       readln(f,vstr);
  422.       if length(vstr)<3 then vstr:=';   oops';      
  423.       if (vstr[1]='D') and (copy(vstr,3,4)=cmpstr) then
  424.       begin
  425.     if not eof(f) then readln(f,revchk);
  426.     if revchk[1]='R' then
  427.     begin
  428.       repeat
  429.         if wrhex(infotbl[8])=copy(revchk,3,2) then vstr:='xxxxxxx'+copy(revchk,6,length(revchk));
  430.         if not eof(f) then readln(f,revchk);
  431.       until revchk[1]<>'R';
  432.     end;
  433.     textcolor(14);
  434.     write(copy(vstr,8,length(vstr)));
  435.     failed:=false;
  436.     textcolor(7);
  437.       end;
  438.     until eof(f) or not failed or (vstr[1]='V');
  439.   end;
  440.   if failed then
  441.   begin
  442.     textcolor(12);
  443.     write('Unknown');
  444.     textcolor(7);
  445.   end;
  446. end;
  447.  
  448.  
  449. procedure showinstallerinfo;
  450. begin
  451.   write('V:',wrhexw(infotbl[1] shl 8+infotbl[0]),' ');
  452.  
  453.   write('D:',wrhexw(infotbl[3] shl 8+infotbl[2]),' ');
  454.  
  455.   write('S:');
  456.   if infotbl[$e] and $7f=0 then
  457.   begin
  458.     write(wrhexw(infotbl[$2f] shl 8+infotbl[$2e]));
  459.     write(wrhexw(infotbl[$2d] shl 8+infotbl[$2c]),' ');
  460.   end else write('00000000 ');
  461.  
  462.   write('B:',bus,' ');
  463.  
  464.   write('E:');
  465.   if deviceid<10 then write('0');
  466.   write(deviceid,' ');
  467.  
  468.   write('F:',func,' ');
  469.  
  470.   write('I:');
  471.   if (infotbl[$3c]<16) and (infotbl[$3c]>0) then
  472.   begin
  473.     if infotbl[$3c]<10 then write('0');
  474.     write(infotbl[$3c],' ');
  475.   end else write('00 ');
  476.  
  477.   write('N:');
  478.   if (infotbl[$3c]<16) and (infotbl[$3c]>0) then
  479.   begin
  480.     if infotbl[$3d]=0 then write('- ') else write(chr(infotbl[$3d]+64),' ');
  481.   end else write('- ');
  482.  
  483.   write('C:');
  484.   write(wrhex(infotbl[$b]),' ');
  485.  
  486.   write('U:');
  487.   write(wrhex(infotbl[$a]),' ');
  488.  
  489.   write('P:');
  490.   write(wrhex(infotbl[$9]),' ');
  491.  
  492.   write('R:');
  493.   write(wrhex(infotbl[$8]),' ');
  494.  
  495.   writeln;
  496. end;
  497.  
  498.  
  499. procedure showroutinginfo;
  500. begin
  501.   writeln('ROM PCI IRQ routing table Windows 9x Compatibility Tests....');
  502.  
  503.  
  504. { Find table }
  505.   i:=0;
  506.   failed:=true;
  507.   repeat
  508.    if (memw[$f000:i]=$5024) and (memw[$f000:i+2]=$5249) then failed:=false;
  509.    if failed then i:=i+16;
  510.   until (i>$ffef) or not failed;
  511.  
  512.  
  513. { check table }
  514.   if not failed then
  515.   begin
  516.     tableok:=true;
  517.  
  518.     writeln(' ROM IRQ routing table found at F000h:',wrhexw(i),'h');
  519.     write(' Table Version ',mem[$f000:i+5],'.',mem[$f000:i+4]);
  520.     if (mem[$f000:i+5]=1) and (mem[$f000:i+4]=0) then writeln(' - OK') else
  521.     begin
  522.       textcolor(12);
  523.       writeln('Invalid Version!');
  524.       textcolor(7);
  525.       tableok:=false;
  526.     end;
  527.  
  528.     write(' Table size ',memw[$f000:i+6],' bytes - ');
  529.     if (memw[$f000:i+6]<33) or (memw[$f000:i+6] mod 16<>0) then
  530.     begin
  531.       textcolor(12);
  532.       writeln('Invalid Size!');
  533.       textcolor(7);
  534.       tableok:=false;
  535.     end else writeln('OK');
  536.  
  537.  
  538.  
  539.     if tableok then
  540.     begin
  541.       write(' Table Checksum ',wrhex(mem[$f000:i+31]),'h - ');
  542.       {$R-}  {Range checking off as sum is DELIBERATELY meant to overfow }
  543.       sum:=0;
  544.       for l:=0 to memw[$f000:i+6]-1 do
  545.       begin
  546.     sum:=sum+mem[$f000:i+l];
  547.       end;
  548.       {$R+}
  549.       if sum=0 then writeln('OK') else
  550.       begin
  551.     textcolor(12);
  552.     writeln('Failed!');
  553.     textcolor(7);
  554.     tableok:=false;
  555.       end;
  556.     end;
  557.  
  558.  
  559.     listmap(memw[$f000:i+10],' IRQ''s dedicated to PCI : ');
  560.  
  561.     if tableok then
  562.     begin
  563.       textcolor(10);
  564.       writeln(' The ROM PCI IRQ routing table appears to be OK.');
  565.       textcolor(7);
  566.     end else
  567.     begin
  568.       textcolor(12);
  569.       writeln(' The ROM PCI IRQ routing table appears to be faulty!!');
  570.       textcolor(7);
  571.     end;
  572.  
  573.   end else
  574.   begin
  575.     textcolor(12);
  576.     writeln('No ROM PCI IRQ routing table found!!!');
  577.     textcolor(7);
  578.   end;
  579. end;
  580.  
  581.  
  582. procedure dohexdump;
  583. begin
  584.   writeln('Hex-Dump of IRQ Routing table : ');
  585.   writeln;
  586.   write('  0000  ');
  587.   for i:=0 to 1023 do
  588.   begin
  589.     if (i>0) and (i mod 16=0) then
  590.     begin
  591.       write('   ');
  592.       for j:=i-16 to i-1 do if ord(irqbuff[j])<32 then write('.') else write(chr(irqbuff[j]));
  593.       writeln;
  594.       write('  ',wrhexw(i),'  ');
  595.     end;
  596.     write(wrhex(irqbuff[i]),' ');
  597.   end;
  598.   write('   ');
  599.   for j:=1008 to 1023 do if ord(irqbuff[j])<32 then write('.') else write(chr(irqbuff[j]));
  600.   writeln;
  601.   writeln;
  602. end;
  603.  
  604.  
  605. procedure docapdecode;
  606. begin
  607.   writeln(' New Capabilities List Present:');
  608. {type 0}     if infotbl[$e] and $7f=0 then cap_ptr:=infotbl[$34];
  609. {type 1}     if infotbl[$e] and $7f=1 then cap_ptr:=infotbl[$34];
  610. {type 2}     if infotbl[$e] and $7f=2 then cap_ptr:=infotbl[$14];
  611.  
  612.   if cap_ptr<>0 then
  613.   repeat
  614.     case infotbl[cap_ptr] of
  615.  
  616.       01 : begin
  617.          write('   Power Management Capability, Version ');
  618.          if infotbl[cap_ptr+2]and 7=2 then writeln('1.1') else
  619.          if infotbl[cap_ptr+2]and 7=1 then writeln('1.0') else
  620.          begin
  621.            textcolor(12);
  622.            writeln('Unknown: Code ',wrhexb(infotbl[cap_ptr+2]and 7),'h');
  623.            textcolor(7);
  624.          end;
  625.  
  626.  
  627. { list supported low-power states; D3 and D0 are always supported}
  628.          if infotbl[cap_ptr+3] and 2=2 then writeln('     Supports low power State D1');
  629.          if infotbl[cap_ptr+3] and 4=4 then writeln('     Supports low power State D2');
  630.          if infotbl[cap_ptr+3] and 6=0 then writeln('     Does not support low power State D1 or D2');
  631.  
  632. {list PME# generation capabilities}         
  633.          if (infotbl[cap_ptr+3] shr 3) = 0 then writeln('     Does not support PME# signalling') else
  634.          begin
  635.            write('     Supports PME# from mode(s) ');
  636.            first:=true;
  637.            if (infotbl[cap_ptr+3] shr 3) and 1=1 then printstatus('D0');
  638.            if (infotbl[cap_ptr+3] shr 3) and 2=2 then printstatus('D1');
  639.            if (infotbl[cap_ptr+3] shr 3) and 4=4 then printstatus('D2');
  640.            if (infotbl[cap_ptr+3] shr 3) and 8=8 then printstatus('D3hot');
  641.            if (infotbl[cap_ptr+3] shr 3) and 16=16 then printstatus('D3cold');
  642.            writeln;
  643.           end;
  644.          
  645.  
  646.          write('     Current Power State : D');
  647.          case infotbl[cap_ptr+4] and 3 of
  648.            0 : writeln('0 (Device operational, no power saving)');
  649.            1 : writeln('1 (Device idle, minimum power saving)');
  650.            2 : writeln('2 (Device CLK stopped, medium power saving)');
  651.            3 : writeln('3hot (Device off: no power to device, maximum power saving)');
  652.          end;
  653.        end;
  654.  
  655.  
  656.       02 : begin
  657.          write('   AGP Capability, Version ');
  658.          write(infotbl[cap_ptr+2] shr 4,'.',infotbl[cap_ptr+2] and $0f,' ');
  659.          if (infotbl[cap_ptr+2] shr 4)=1 then writeln('(AGP 1x and/or 2x support)');
  660.          if (infotbl[cap_ptr+2] shr 4)=2 then writeln('(AGP 4x and below support)');
  661.          if (infotbl[cap_ptr+2] shr 4)=3 then
  662.          begin
  663.            write('(AGP 8x and 4x');
  664.            if (infotbl[cap_ptr+2] and $0f)<5 then write(', core register');
  665.            if ((infotbl[cap_ptr+2] and $0f)>4) and
  666.          ((infotbl[cap_ptr+2] and $0f)<10) then write(', appendix register');
  667.            writeln(' support)');
  668.          end;
  669.  
  670.  
  671.  
  672. { Status register }
  673.  
  674.          write('     AGP Speed(s) Supported : ');
  675.          if infotbl[cap_ptr+4] and 8=8 then
  676.          begin
  677.            if infotbl[cap_ptr+4] and 1=1 then write('4x ');
  678.            if infotbl[cap_ptr+4] and 2=2 then write('8x ');
  679.            if infotbl[cap_ptr+4] and 7>3 then write('Unknown Speed Reported (',wrhex(infotbl[cap_ptr+4] and 7),'h)!!');
  680.          end else
  681.          begin
  682.            if infotbl[cap_ptr+4] and 1=1 then write('1x ');
  683.            if infotbl[cap_ptr+4] and 2=2 then write('2x ');
  684.            if infotbl[cap_ptr+4] and 4=4 then write('4x ');
  685.            if infotbl[cap_ptr+4] and 7=0 then
  686.            begin
  687.                  textcolor(12);
  688.          write('None!!');
  689.                  textcolor(11);
  690.          write(' (Assume Only 1x Support)');
  691.                  textcolor(7);
  692.            end;
  693.          end;
  694.          writeln;
  695.  
  696.          write('     FW Transfers Supported : ');
  697.          if infotbl[cap_ptr+4] and $10=$10 then writeln('Yes') else writeln('No');
  698.  
  699.          write('     >4Gb Address Space Supported : ');
  700.          if infotbl[cap_ptr+4] and $20=$20 then writeln('Yes') else writeln('No');
  701.  
  702.          write('     Sideband Addressing Supported : ');
  703.          if infotbl[cap_ptr+5] and 2=2 then writeln('Yes') else writeln('No');
  704.  
  705. { if v3.? reported, see if v3.0 mode is on }
  706.          if (infotbl[cap_ptr+2] shr 4)=3 then
  707.          begin
  708.            write('     AGP v3.0 Operation Mode Available : ');
  709.            if infotbl[cap_ptr+4] and 8=8 then writeln('Yes') else writeln('No');
  710.          end;
  711.  
  712. { isosynch only in AGP v3.0 mode }
  713.          if infotbl[cap_ptr+4] and 8=8 then
  714.          begin
  715.            write('     Isosynchronous Transactions Supported : ');
  716.            if infotbl[cap_ptr+6] and 2=2 then writeln('Yes') else writeln('No');
  717.          end;
  718.  
  719.  
  720.          write('     Maximum Command Queue Length : ',infotbl[cap_ptr+7]+1,' byte');
  721.          if infotbl[cap_ptr+7]=0 then writeln else writeln('s');
  722.  
  723. { Command register }
  724.  
  725.          write('     AGP Speed Selected : ');
  726.          if infotbl[cap_ptr+4] and 8=8 then
  727.          begin
  728.            if infotbl[cap_ptr+8] and 7=1 then write('4x ');
  729.            if infotbl[cap_ptr+8] and 7=2 then write('8x ');
  730.            if infotbl[cap_ptr+8] and 7>2 then write('Unknown Speed Reported (',wrhex(infotbl[cap_ptr+8] and 7),'h)!!');
  731.            if infotbl[cap_ptr+8] and 7=0 then write('None Selected');
  732.          end else
  733.          begin
  734.            if infotbl[cap_ptr+8] and 7=1 then write('1x ');
  735.            if infotbl[cap_ptr+8] and 7=2 then write('2x ');
  736.            if infotbl[cap_ptr+8] and 7=4 then write('4x ');
  737.            if infotbl[cap_ptr+8] and 7=0 then write('None Selected');
  738.          end;
  739.          writeln;
  740.  
  741.          write('     FW Transfers Enabled : ');
  742.          if infotbl[cap_ptr+8] and $10=$10 then writeln('Yes') else writeln('No');
  743.  
  744.          write('     >4Gb Address Space Enabled : ');
  745.          if infotbl[cap_ptr+8] and $20=$20 then writeln('Yes') else writeln('No');
  746.  
  747.          write('     AGP Enabled : ');
  748.          if infotbl[cap_ptr+9] and 1=1 then
  749.          begin
  750.                textcolor(10);
  751.            writeln('Yes');
  752.                textcolor(7);
  753.           end else
  754.           begin
  755.                 textcolor(12);
  756.                 writeln('No');
  757.                 textcolor(7);
  758.           end;
  759.  
  760.          write('     Sideband Addressing Enabled : ');
  761.          if infotbl[cap_ptr+9] and 2=2 then writeln('Yes') else writeln('No');
  762.  
  763.          if infotbl[cap_ptr+4] and 8=8 then
  764.          begin
  765.            write('     AGP v3.0 Operation Mode : ');
  766.            if infotbl[cap_ptr+9] and 1=1 then writeln('Enabled') else writeln('Disabled');
  767.          end;
  768.  
  769.          write('     Current Command Queue Length : ',infotbl[cap_ptr+11]+1,' byte');
  770.          if infotbl[cap_ptr+11]=0 then writeln else writeln('s');
  771.        end;
  772.  
  773.  
  774.       03 : begin
  775.          writeln('   Vital Product Data Capability');
  776.        end;
  777.  
  778.  
  779.       04 : begin
  780.          writeln('   Slot Identification Capability');
  781.  
  782.          write('     This is ');
  783.          if infotbl[cap_ptr+2] and $20=0 then write('not ');
  784.          writeln('a parent bridge');
  785.  
  786.          write('     Number of slots on secondary side of this bridge : ');
  787.          writeln(infotbl[cap_ptr+2] and $1f);
  788.  
  789.          writeln('Chassis Number : ',infotbl[cap_ptr+3]);
  790.        end;
  791.  
  792.  
  793.       05 : begin
  794.          writeln('   Message Signalled Interrupt Capability');
  795.          write('     MSI is ');
  796.          if infotbl[cap_ptr+2] and 1=1 then writeln('enabled') else writeln('disabled');
  797.  
  798.          write('     MSI function can generate ');
  799.          if infotbl[cap_ptr+2] and 128=128 then writeln('64') else write('32');
  800.          writeln('-bit addresses');
  801.         end;
  802.  
  803.  
  804.       06 : begin
  805.          writeln('   CompactPCI Hot-Swap Capability');
  806.        end;
  807.  
  808.  
  809.       07 : begin
  810.          writeln('   PCI-X Capability');
  811.  
  812. { type 1 }
  813.          if infotbl[$e] and $7f=1 then
  814.          begin
  815.            write('     Secondary AD Bus size is ');
  816.            if infotbl[cap_ptr+2] and 1=1 then write('64') else write('32');
  817.            writeln('-bit');
  818.  
  819.            write('     Secondary AD Bus Maximum Speed in PCI-X mode is ');
  820.            if infotbl[cap_ptr+2] and 2=2 then write('133') else write('66');
  821.            writeln('MHz');
  822.  
  823.            write('     Seconday AD Bus Current Speed : ');
  824.            case ((infotbl[cap_ptr+3] and 1) shl 8 + (infotbl[cap_ptr+2] and $c0) shr 6) of
  825.          0 : write('33');
  826.          1 : write('66');
  827.          2 : write('100');
  828.          3 : write('133');
  829.          4..7 : write('Unknown!');
  830.            end;
  831.  
  832.          end;
  833.  
  834. { type 0 and 1 }
  835.          write('     Primary AD Bus size is ');
  836.          if infotbl[cap_ptr+6] and 1=1 then write('64') else write('32');
  837.          writeln('-bit');
  838.  
  839.          write('     Primary AD Bus Maximum Speed in PCI-X mode is ');
  840.          if infotbl[cap_ptr+6] and 2=2 then write('133') else write('66');
  841.          writeln('MHz');
  842.        end;
  843.  
  844.       08 : begin
  845.              writeln('   HyperTransport Capability');
  846.            end;
  847.  
  848.       09 : begin
  849.          writeln('   Vendor-Dependant Capability');
  850.        end;
  851.  
  852.      $0a : begin
  853.          writeln('   Debug Port Capability');
  854.        end;
  855.  
  856.      $0b : begin
  857.          writeln('   CompactPCI Resource Control Capability');
  858.        end;
  859.  
  860.      $0c : begin
  861.          writeln('   PCI Hot-Plug Capability');
  862.        end;
  863.  
  864.      $0e : begin
  865.          writeln('   AGP 8x Capability');
  866.        end;
  867.  
  868.      $0f : begin
  869.          writeln('   Secure Device Capability');
  870.        end;
  871.  
  872.      $10 : begin
  873.          writeln('   PCI Express Capability, Version ',infotbl[cap_ptr+2] and $f);
  874.  
  875.  
  876. { **** 3GIO Capabilities field 2-3}
  877.          write('     Device/Port Type : ');
  878.          case infotbl[cap_ptr+2] shr 4 of
  879.            0 : writeln('PCI Express Endpoint Device');
  880.            1 : writeln('Legacy PCI Express Endpoint Device');
  881.            4 : writeln('Root port of PCI Express Root Complex');
  882.            5 : writeln('Upstream port of PCI Express Switch');
  883.            6 : writeln('Downstream port of PCI Express Switch');
  884.            7 : writeln('PCI Express to PCI/PCI-X Bridge');
  885.            else writeln('Unknown (',wrhex(infotbl[cap_ptr+2] shr 4),'h)!!');
  886.           end;
  887.  
  888. { ports only }                
  889.           if (infotbl[cap_ptr+2] shr 4=4) or (infotbl[cap_ptr+2] shr 4=6) then
  890.           begin
  891.             write('     Port is an ');
  892.             if infotbl[cap_ptr+3] and 1=1 then writeln('Expansion Slot') else writeln('Integrated Device');
  893.           end;
  894.  
  895. { **** Device Capabilities field 4-7}          
  896. { devices only }          
  897.           if (infotbl[cap_ptr+2] shr 4=0) or (infotbl[cap_ptr+2] shr 4=1) then
  898.           begin
  899.               if infotbl[cap_ptr+5] and 16=16 then writeln('     Attention Button Present on Device');
  900.             if infotbl[cap_ptr+5] and 32=32 then writeln('     Attention Indicator Present on Device');
  901.             if infotbl[cap_ptr+5] and 64=64 then writeln('     Power Indicator Present on Device');
  902.           end;
  903.  
  904. { upstream ports only }
  905.           if infotbl[cap_ptr+2] shr 4=5 then
  906.           begin
  907.               write('     Slot Power Limit Value : ');
  908.         spl:=(infotbl[cap_ptr+6] shr 2) + ((infotbl[cap_ptr+7] and 3) shl 6);
  909.               if ((infotbl[cap_ptr+7] and $c) shr 2)=0 then spl:=spl;
  910.               if ((infotbl[cap_ptr+7] and $c) shr 2)=1 then spl:=spl*0.1;
  911.               if ((infotbl[cap_ptr+7] and $c) shr 2)=2 then spl:=spl*0.01;
  912.               if ((infotbl[cap_ptr+7] and $c) shr 2)=3 then spl:=spl*0.001;
  913.               writeln(spl,' Watts');
  914.             end;
  915.             
  916. { **** Device Control Field 8-9}
  917.             if infotbl[cap_ptr+8] and 1=1 then writeln('     Correctable Error Reporting Enabled');
  918.             if infotbl[cap_ptr+8] and 2=2 then writeln('     Non-Fatal Error Reporting Enabled');
  919.             if infotbl[cap_ptr+8] and 4=4 then writeln('     Fatal Error Reporting Enabled');
  920.             if infotbl[cap_ptr+8] and 8=8 then writeln('     Unsupported Request Reporting Enabled');
  921.             write('     Unsupported Request Severity is ');
  922.             if infotbl[cap_ptr+8] and 16=16 then writeln('Fatal') else writeln('Non-Fatal');
  923.  
  924.  
  925. { **** Device Status field 0ah-0bh}
  926.             if infotbl[cap_ptr+$a] and 1=1 then writeln('     Correctable Error Detected');
  927.             if infotbl[cap_ptr+$a] and 2=2 then writeln('     Non-Fatal Error Detected');
  928.             if infotbl[cap_ptr+$a] and 4=4 then writeln('     Fatal Error Detected');
  929.             if infotbl[cap_ptr+$a] and 8=8 then writeln('     Unsupported Request Detected');
  930.             if infotbl[cap_ptr+$a] and 16=16 then writeln('     AUX Power Detected');
  931.             if infotbl[cap_ptr+$a] and 32=32 then writeln('     Device Reports Transactions Pending');
  932.  
  933.           
  934. { **** Link Capabilities field 0ch-0fh}
  935.           write('     Maximum Link speed : ');
  936.           case infotbl[cap_ptr+$c] and $f of
  937.             1 : writeln('2.5Gb/s');
  938.             else writeln('Unknown (',wrhex(infotbl[cap_ptr+$c] and $f),'h)!!');
  939.           end;
  940.  
  941.           write('     Maximum Link Width : x');
  942.           lw:=((infotbl[cap_ptr+$d] and 3) shl 4) + ((infotbl[cap_ptr+$c] and $f0) shr 4);
  943.           if lw=0 then writeln('Reserved') else writeln(lw);
  944.  
  945.           writeln('     Link Port Number   : ',infotbl[cap_ptr+$f]);
  946.      
  947. { **** Link Control 10h-11h }
  948.  
  949.             if infotbl[cap_ptr+$10] and 4=4 then writeln('     Link is in Loopback mode');
  950.             if infotbl[cap_ptr+$10] and 16=16 then writeln('     Link is Disabled');
  951.           if infotbl[cap_ptr+$10] and 64=64 then writeln('     Common Clock Configuration In Use')
  952.         else writeln('Asynchronous Clocking in Use');
  953.  
  954.  
  955. { **** Link Status 12h-13h } 
  956.               write('     Current Link speed : ');
  957.           case infotbl[cap_ptr+$12] and $f of
  958.             1 : writeln('2.5Gb/s');
  959.             else writeln('Unknown (',wrhex(infotbl[cap_ptr+$c] and $f),')!!');
  960.           end;
  961.           
  962.           write('     Current Link Width : x');
  963.           lw:=((infotbl[cap_ptr+$13] and 3) shl 4) + ((infotbl[cap_ptr+$12] and $f0) shr 4);
  964.           if infotbl[cap_ptr+$13] and 8=8 then writeln('??') else writeln(lw);
  965.           if infotbl[cap_ptr+$13] and 4=4 then writeln('     Link Training Error Reported!!');
  966.           if infotbl[cap_ptr+$13] and 8=8 then writeln('     Link Training Currently In Progress!!');
  967.  
  968. { **** Slot Capabilities 14h-17h, slots & root ports only }
  969.            if (infotbl[cap_ptr+2] shr 4)>1 then
  970.            begin
  971.              if infotbl[cap_ptr+$14] and 1=1 then writeln('     Attention Button Present');
  972.              if infotbl[cap_ptr+$14] and 2=2 then writeln('     Power Controller Present');
  973.              if infotbl[cap_ptr+$14] and 4=4 then writeln('     MRL Sensor Present');
  974.              if infotbl[cap_ptr+$14] and 8=8 then writeln('     Attention Indicator Present');
  975.              if infotbl[cap_ptr+$14] and 16=16 then writeln('     Power Indicator Present');
  976.              if infotbl[cap_ptr+$14] and 32=32 then writeln('     Hot Plug Surprise is Possible');
  977.              if infotbl[cap_ptr+$14] and 64=64 then writeln('     Hot Plug Capable');
  978.            
  979.              writeln('     Physical slot Number ',(word(word(infotbl[cap_ptr+$17]) shl 2)+(infotbl[cap_ptr+$16] shr 6)));
  980.          end;
  981.        end;
  982.  
  983.        
  984.  
  985.      $11 : begin
  986.          writeln('   MSI-X Capability');
  987.        end;
  988.  
  989.  
  990.       else writeln('   Unknown Capability (Code ',wrhex(infotbl[cap_ptr]),'h)!!');
  991.     end;
  992.   cap_ptr:=infotbl[cap_ptr+1];
  993.   until cap_ptr=0 else writeln('  No ''New Capabilities'' Are Currently Enabled!');
  994. end;
  995.  
  996.  
  997.  
  998.  
  999. procedure showallinfo;
  1000. var
  1001.   j,
  1002.   i     : integer;
  1003.   pp,
  1004.   nn,
  1005.   x    : byte;
  1006.   gotit    : boolean;
  1007.  
  1008. begin
  1009.     if businfo then
  1010.     begin
  1011.       write(' Bus ');
  1012.       textcolor(11);
  1013.       write(bus);
  1014.       textcolor(7);
  1015.       write(' (');
  1016.  
  1017. { look for CardBus }
  1018.       gotit:=false;
  1019.       if cardptr>0 then
  1020.       begin
  1021.         for x:=1 to cardptr do if bus=cardbus[x] then
  1022.         begin
  1023.           write('Cardbus');
  1024.           gotit:=true;
  1025.         end;
  1026.       end;
  1027.  
  1028.  
  1029. { look for PCI Express }
  1030. {type 0}  if infotbl[$e] and $7f=0 then cap_ptr:=infotbl[$34];
  1031. {type 1}  if infotbl[$e] and $7f=1 then cap_ptr:=infotbl[$34];
  1032. {type 2}  if infotbl[$e] and $7f=2 then cap_ptr:=infotbl[$14];
  1033.           if cap_ptr<>0 then
  1034.           repeat
  1035.             if infotbl[cap_ptr]=$10 then
  1036.             begin
  1037.               write('PCI Express');
  1038.               gotit:=true;
  1039.             end;
  1040.             cap_ptr:=infotbl[cap_ptr+1];
  1041.           until cap_ptr=0;
  1042.  
  1043.  
  1044. { we crudely assume bus x is AGP if it's got the VGA Mapping flag set on it's parent PCI bridge - this is probably
  1045.   not prefect, but will do for now!!
  1046.  
  1047.   It's wrong because on a board with an AGP slot but no AGP card inserted, VGA Mapping will be off. This could also
  1048.   be the case if the AGP card isn't the primary adapter (eg a PCI one is). This is more accurate than previous
  1049.   attempts, however, as it avoids the situation where a board with bridges but without AGP is falsely reported.
  1050.   
  1051.   Previously, we could get false positives (very bad); now we get false negitives (not so bad, but still not perfect) }
  1052.  
  1053.  
  1054.  
  1055. { try to guess AGP bus number by looking for a set VGA Mapping flag on a PCI-PCI Bridge. This works because the host
  1056.   bridge will always appear before it's own child busses... ie this 'detects' the bus, the next block actually reports
  1057.   the results in a later iteration (when the right bus number is finally reached) }
  1058.  
  1059.       if infotbl[$e] and $7f=1 then if infotbl[$3e] and 8=8 then agpbusnum:=infotbl[$19];
  1060.  
  1061. { assume plain old PCI if nothing else matches }
  1062.       if not gotit then if bus=agpbusnum then write('AGP') else write('PCI');
  1063.       write('), Device Number ');
  1064.           textcolor(11);
  1065.       write(deviceid);
  1066.           textcolor(7);
  1067.       write(', Device Function ');
  1068.           textcolor(11);
  1069.       writeln(func);
  1070.           textcolor(7);
  1071.     end;
  1072.  
  1073.  
  1074.       if installermode then showinstallerinfo else
  1075.       begin
  1076.  
  1077.  
  1078.  
  1079.  
  1080.       write(' Vendor ',wrhexw(infotbl[1] shl 8+infotbl[0]),'h ');
  1081.       cmpstr:=wrhexw(infotbl[1] shl 8+infotbl[0]);
  1082.       lookupven(false);
  1083.       writeln;
  1084.  
  1085.  
  1086.       write(' Device ',wrhexw(infotbl[3] shl 8+infotbl[2]),'h ');
  1087.       cmpstr:=wrhexw(infotbl[3] shl 8+infotbl[2]);
  1088.       lookupdev;
  1089.       writeln;
  1090.  
  1091.  
  1092.       if not summary then
  1093.       begin
  1094.         write(' Command ',wrhexw(infotbl[5] shl 8+infotbl[4]),'h');
  1095.         first:=true;
  1096.         write(' (');
  1097.         if infotbl[4] and 1=1 then printstatus('I/O Access');
  1098.         if infotbl[4] and 2=2 then printstatus('Memory Access');
  1099.         if infotbl[4] and 3=0 then printstatus('Bus Access Disabled!!');
  1100.         if infotbl[4] and 4=4 then printstatus('BusMaster');
  1101.         if infotbl[4] and 8=8 then printstatus('Special Cycles');
  1102.         if infotbl[4] and 16=16 then printstatus('MemWrite+Invalidate');
  1103.         if infotbl[4] and 32=32 then printstatus('VGA Palette Snoop');
  1104.         if infotbl[4] and 64=64 then printstatus('Parity Error Response');
  1105.         if infotbl[4] and 128=128 then printstatus('Wait Cycles');
  1106.         if infotbl[5] and 1=1 then printstatus('System Errors');
  1107.         if infotbl[5] and 2=2 then printstatus('Back-To-Back Transactions');
  1108.         if infotbl[5] and 4=4 then printstatus('Interrupt Disable');
  1109.         writeln(')');
  1110.  
  1111.  
  1112.         write(' Status ',wrhexw(infotbl[7] shl 8+infotbl[6]),'h');
  1113.         if (infotbl[6]<>0) or (infotbl[7]<>0) then
  1114.         begin
  1115.           first:=true;
  1116.           write(' (');
  1117.           if infotbl[6] and 8=8 then printstatus('Signalled Interrupt');
  1118.           if infotbl[6] and 16=16 then printstatus('Has Capabilities List');
  1119.           if infotbl[6] and 32=32 then printstatus('Supports 66MHz');
  1120.           if infotbl[6] and 64=64 then printstatus('Has UDF');
  1121.           if infotbl[6] and 128=128 then printstatus('Supports Back-To-Back Trans.');
  1122.  
  1123.           if infotbl[7] and 1=1 then printstatus('Data parity Error Detected');
  1124.           if infotbl[7] and 8=8 then printstatus('Signalled Target Abort');
  1125.           if infotbl[7] and 16=16 then printstatus('Received Target Abort');
  1126.           if infotbl[7] and 32=32 then printstatus('Received Master Abort');
  1127.           if infotbl[7] and 64=64 then printstatus('Signalled System Error');
  1128.           if infotbl[7] and 128=128 then printstatus('Detected Parity Error');
  1129.  
  1130.           case ((infotbl[7] and 6) shr 1) of
  1131.         0 : printstatus('Fast Timing');
  1132.         1 : printstatus('Medium Timing');
  1133.         2 : printstatus('Slow Timing');
  1134.         3 : printstatus('Unknown Timing');
  1135.           end;
  1136.           write(')');
  1137.  
  1138.         end;
  1139.         writeln;
  1140.  
  1141.         write(' Revision ',wrhex(infotbl[8]),'h');
  1142.         write(', Header Type ',wrhex(infotbl[$e]),'h');
  1143.         writeln(', Bus Latency ',wrhex(infotbl[$d]),'h');
  1144.  
  1145.  
  1146.         write(' Self test ',wrhex(infotbl[$f]),'h (Self test ');
  1147.         if infotbl[$f] and $80=0 then write('not ');
  1148.         write('supported');
  1149.  
  1150.  
  1151.         if infotbl[$f] and $80=$80 then
  1152.         begin
  1153.           write(': Completion code ',wrhexb(infotbl[$f] and $f),'h - ');
  1154.           if infotbl[$f] and $f=0 then
  1155.           begin
  1156.         textcolor(10);
  1157.         write('OK');
  1158.         textcolor(7);
  1159.           end else
  1160.           begin
  1161.         textcolor(12);
  1162.         write('Failed!!');
  1163.         textcolor(7);
  1164.           end;
  1165.         end;
  1166.  
  1167.         writeln(')');
  1168.  
  1169.  
  1170.         if infotbl[$c]<>0 then writeln(' Cache line size ',infotbl[$c]*4,' Bytes (',infotbl[$c],' DWords)');
  1171.  
  1172. { class code stuff }
  1173.  
  1174.         write(' PCI Class ');
  1175.  
  1176.         if infotbl[$b]=$ff then
  1177.         begin
  1178.           write('FFh ');
  1179.           textcolor(10);
  1180.           write('(does not meet any PCI-SIG defined class)');
  1181.           textcolor(7);
  1182.         end else
  1183.         begin
  1184.  
  1185.  
  1186.         for i:=0 to high_class_name do
  1187.         if infotbl[$b]=i then
  1188.           begin
  1189.           textcolor(14);
  1190.           write(PCI_class_names[i]);
  1191.           textcolor(7);
  1192.         end;
  1193.  
  1194.         write(', type ');
  1195.  
  1196.  
  1197.         found:=false;
  1198.  
  1199.         for i:=0 to high_class_array do
  1200.          begin
  1201.           if (pci_class_array[i].class=infotbl[$b]) and
  1202.           (pci_class_array[i].subclass=infotbl[$a]) and
  1203.           (pci_class_array[i].progif=infotbl[$9]) then
  1204.           begin
  1205.         found:=true;
  1206.         textcolor(14);
  1207.         write(PCI_class_array[i].name);
  1208.         textcolor(7);
  1209.           end;
  1210.         end;
  1211.  
  1212.  
  1213.         if not found then
  1214.         begin
  1215.           for i:=0 to high_class_array do
  1216.           begin
  1217.         if (pci_class_array[i].class=infotbl[$b]) and
  1218.         (pci_class_array[i].subclass=infotbl[$a]) then
  1219.         begin
  1220.           found:=true;
  1221.           textcolor(14);
  1222.           write(PCI_class_array[i].name);
  1223.           textcolor(7);
  1224.         end;
  1225.           end;
  1226.         end;
  1227.  
  1228.  
  1229.         if not found then
  1230.         begin
  1231.           textcolor(12);
  1232.           write('Unknown!');
  1233.           textcolor(7);
  1234.         end;
  1235.  
  1236.  
  1237.         end;
  1238.  
  1239.  
  1240.         writeln;
  1241.       end;
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.       if not summary then
  1249.       begin
  1250. { look for generic PCI IDE controller & decode it's info, if present }
  1251.        if (infotbl[$b]=01) and (infotbl[$a]=01) then
  1252.        begin
  1253.          writeln(' PCI EIDE Controller Features :');
  1254.          write('   BusMaster EIDE is ');
  1255.          if infotbl[$9] and $80=0 then
  1256.          begin
  1257.            textcolor(12);
  1258.            write('NOT ');
  1259.            textcolor(7);
  1260.          end;
  1261.          writeln('supported');
  1262.  
  1263.          write('   Primary   Channel is ');
  1264.          if infotbl[$9] and 1=0 then
  1265.          begin
  1266.            writeln('at I/O Port 01F0h and IRQ 14');
  1267.            if infotbl[$3c]<>14 then inc(irqmap[14]);
  1268.          end else writeln('in native mode at Addresses 0 & 1');
  1269.          write('   Secondary Channel is ');
  1270.          if infotbl[$9] and 4=0 then
  1271.          begin
  1272.            writeln('at I/O Port 0170h and IRQ 15');
  1273.            if infotbl[$3c]<>15 then inc(irqmap[15]);
  1274.          end else writeln('in native mode at Addresses 2 & 3');
  1275.        end;
  1276.  
  1277.        end else
  1278.        begin
  1279. { summary mode: pick up IRQs only }
  1280.          if (infotbl[$b]=01) and (infotbl[$a]=01) then
  1281.          begin
  1282.            if (infotbl[$9] and 1=0) and (infotbl[$3c]<>14) then inc(irqmap[14]);
  1283.            if (infotbl[$9] and 4=0) and (infotbl[$3c]<>15) then inc(irqmap[15]);
  1284.          end;
  1285.        end;
  1286.  
  1287.  
  1288.  
  1289.  
  1290. { if type 0 table & if Subsystem ID exists, display and scan file for match }
  1291.        if infotbl[$e] and $7f=0 then
  1292.        if (infotbl[$2c]<>0) or (infotbl[$2d]<>0) or (infotbl[$2e]<>0) or (infotbl[$2f]<>0) then
  1293.        begin
  1294.  
  1295. { subsystem ID }
  1296.  
  1297.  
  1298.          write(' Subsystem ID ',wrhexw(infotbl[$2f] shl 8+infotbl[$2e]));
  1299.          write(wrhexw(infotbl[$2d] shl 8+infotbl[$2c]),'h');
  1300.          cmpstr:=wrhexw(infotbl[$2f] shl 8+infotbl[$2e])+wrhexw(infotbl[$2d] shl 8+infotbl[$2c]);
  1301.  
  1302.  
  1303.          genssid:=false;
  1304.          if (infotbl[$2c]=infotbl[0])
  1305.          and (infotbl[$2d]=infotbl[1])
  1306.          and (infotbl[$2e]=infotbl[2])
  1307.          and (infotbl[$2f]=infotbl[3]) then genssid:=true;
  1308.  
  1309.          oemidnum:='';
  1310.          oemidstr:='';
  1311.          bogusid:=false;
  1312.  
  1313.  
  1314.          failed:=true;
  1315.          userev:=true;
  1316.          if not eof(f) then
  1317.          begin
  1318.            repeat
  1319. {!!}         if userev then vstr:=revchk else readln(f,vstr);
  1320.          userev:=false;
  1321.  
  1322.  
  1323. { OEM Vendor ID }
  1324.          if vstr[1]='O' then
  1325.          begin
  1326.            if copy(vstr,3,4)=copy(cmpstr,5,4) then
  1327.            begin
  1328.              oemidstr:=copy(vstr,8,length(vstr)); { closest match }
  1329.              oemidnum:=copy(vstr,3,4); { matching vendor name }
  1330.            end;
  1331.          end;
  1332.  
  1333.  
  1334.          if vstr[1]='S' then
  1335.          begin
  1336.            if copy(vstr,3,4)=copy(cmpstr,1,4) then
  1337.            begin
  1338.              if oemidnum<>'' then
  1339.              begin
  1340.                oemidstr:=copy(vstr,8,length(vstr));
  1341.                begin
  1342.              textcolor(14);
  1343.              write(' ',oemidstr);
  1344.              if genssid then
  1345.              begin
  1346.                textcolor(11);
  1347.                writeln(' (Generic ID)')
  1348.              end else writeln;
  1349.              failed:=false;
  1350.              textcolor(7);
  1351.                end;
  1352.              end;
  1353.            end;
  1354.          end;
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362. { Oddball 8 digit entry }
  1363.          if (vstr[1]='X') and (copy(vstr,3,8)=cmpstr) then
  1364.          begin
  1365.            oemidnum:=copy(vstr,7,4); { matching vendor name }
  1366.            bogusid:=true;
  1367.            textcolor(14);
  1368.            write(' ',copy(vstr,12,length(vstr)));
  1369.            if genssid then
  1370.            begin
  1371.              textcolor(11);
  1372.              writeln(' (Generic ID)')
  1373.            end else writeln;
  1374.            failed:=false;
  1375.            textcolor(7);
  1376.          end;
  1377.  
  1378.  
  1379. { remember to ignore comment lines here also!!! }
  1380.  
  1381.            until eof(f) or not failed or ((vstr[1]<>'O') and (vstr[1]<>'X') and (vstr[1]<>'S') and(vstr[1]<>';'));
  1382.          end;
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.          if failed then
  1390.          begin
  1391.            if oemidstr<>'' then
  1392.            begin
  1393.          textcolor(14);
  1394.          write(' ',oemidstr);
  1395.          textcolor(15);
  1396.          write(' (Guess Only!)');
  1397.          textcolor(7);
  1398.            end else
  1399.            begin
  1400.          textcolor(12);
  1401.          write(' Unknown');
  1402.            end;
  1403.  
  1404.            if genssid then
  1405.            begin
  1406.          textcolor(11);
  1407.          writeln(' (Generic ID)')
  1408.            end else writeln;
  1409.            textcolor(7);
  1410.          end;
  1411.  
  1412.  
  1413. { subsystem vendor }
  1414.          write(' Subsystem Vendor ',wrhexw(infotbl[$2d] shl 8+infotbl[$2c]),'h');
  1415.  
  1416.          if bogusid then
  1417.          begin
  1418.            textcolor(15);
  1419.            writeln(' Known Bad Subsystem ID - no Vendor ID Available');
  1420.            textcolor(7);
  1421.          end else
  1422.          begin
  1423.            if oemidnum<>'' then cmpstr:=oemidnum
  1424.            else cmpstr:=wrhexw(infotbl[$2d] shl 8+infotbl[$2c]);
  1425.            close(f);        { get back to start of file, as the}
  1426.            reset(f);        { subsys vendor may be higher up...!}
  1427.            failed:=true;
  1428.            if not eof(f) then
  1429.            begin
  1430.          repeat
  1431.            readln(f,vstr);
  1432.                    if length(vstr)<3 then vstr:=';   oops';
  1433.            if (vstr[1]='V') and (copy(vstr,3,4)=cmpstr) then
  1434.            begin
  1435.              textcolor(14);
  1436.              writeln(' ',copy(vstr,8,length(vstr)));
  1437.              failed:=false;
  1438.              textcolor(7);
  1439.            end;
  1440.          until eof(f) or not failed;
  1441.            end;
  1442.            if failed then
  1443.            begin
  1444.          textcolor(12);
  1445.          writeln(' Unknown');
  1446.          textcolor(7);
  1447.            end;
  1448.          end;
  1449.        end;
  1450. { always }
  1451.        close(f);
  1452.  
  1453.  
  1454.  
  1455.  
  1456. { Memory & I/O  registers }
  1457.        if not summary then
  1458.        begin
  1459. { type 0 header = 6 entries, type 1 = 2, type 2 = skip }
  1460.        pp:=0;
  1461.        if infotbl[$e] and $7f=0 then pp:=5;
  1462.        if infotbl[$e] and $7f=1 then pp:=1;
  1463.  
  1464.        if pp>0 then for nn:=0 to pp do
  1465.        begin
  1466.          if infotbl[$10+(nn*4)]+infotbl[$11+(nn*4)]+
  1467.            infotbl[$12+(nn*4)]+infotbl[$13+(nn*4)]<>0 then
  1468.          begin
  1469.            write(' Address ',nn,' is a');
  1470.            if infotbl[$10+(nn*4)] and 1=1 then
  1471.            begin
  1472.          write('n I/O Port : ');
  1473.          addr:=infotbl[$13+(nn*4)] shl 8 + infotbl[$12+(nn*4)];
  1474.          write(wrhexw(addr));
  1475.          addr:=infotbl[$11+(nn*4)] shl 8 + (infotbl[$10+(nn*4)] and $fc);
  1476.          write(wrhexw(addr),'h');
  1477.            end else
  1478.            begin
  1479.          write(' Memory Address');
  1480.          if infotbl[$10+(nn*4)] and 6=0 then write(' (anywhere in 0-4Gb');
  1481.          if infotbl[$10+(nn*4)] and 6=2 then write(' (below 1Mb');
  1482.          if infotbl[$10+(nn*4)] and 6=4 then write(' (anywhere in 64-bit space');
  1483.          if infotbl[$10+(nn*4)] and 6=6 then write(' (reserved');
  1484.          if infotbl[$10+(nn*4)] and 8=8 then write(', Prefetchable) : ') else write(') : ');
  1485.          addr:=infotbl[$13+(nn*4)] shl 8 + infotbl[$12+(nn*4)];
  1486.          write(wrhexw(addr));
  1487.          addr:=infotbl[$11+(nn*4)] shl 8 + (infotbl[$10+(nn*4)] and $f0);
  1488.          write(wrhexw(addr)+'h');
  1489.            end;
  1490.  
  1491. { size the register ?? }
  1492.  
  1493.            writeln;
  1494.          end;
  1495.        end;
  1496.  
  1497.  
  1498.        end;
  1499.  
  1500.  
  1501. { all header types - list IRQ, if present }
  1502.        if (infotbl[$3c]<16) and (infotbl[$3c]>0) then
  1503.        begin
  1504.          write(' System IRQ ',infotbl[$3c],', INT# ');
  1505.          if infotbl[$3d]=0 then write('-') else write(chr(infotbl[$3d]+64));
  1506.          writeln;
  1507.          inc(irqmap[infotbl[$3c]]);
  1508.        end;
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514. { type 0,1 header - List ExpROM, if present }
  1515.        if not summary then
  1516.        begin
  1517.        if (infotbl[$e] and $7f=0) or (infotbl[$e] and $7f=1) then
  1518.        begin
  1519.          if infotbl[$e] and $7f=0 then lb:=$30;
  1520.          if infotbl[$e] and $7f=1 then lb:=$38;
  1521.          if usebios then write_dword_bios(deviceid,func,bus,lb,$ffff,$fffe) else write_dword_hw(deviceid,func,bus,lb,$ffff,$fffe);
  1522.          for i:=lb to lb+3 do
  1523.          if usebios then infotbl[i]:=lookup_bios(deviceid,func,bus,i) else infotbl[i]:=lookup_hw(deviceid,func,bus,i);
  1524. { if any bit = 1, we have expROM }
  1525.            if (infotbl[lb+3]<>0) or (infotbl[lb+2]<>0) or (infotbl[lb+1]<>0) or (infotbl[lb]<>0)then
  1526.          begin
  1527. { find lowest 1-bit, gives expROM size }
  1528.              romsize:=1;
  1529.              romresult:=infotbl[lb+3] shl 24 + infotbl[lb+2] shl 16 + infotbl[lb+1] shl 8 + infotbl[lb];
  1530.              found:=false;
  1531.              repeat
  1532.                if romresult and romsize=romsize then found:=true else romsize:=romsize shl 1;
  1533.              until found or (romsize=0);
  1534.              romsize:=trunc(romsize/1024);
  1535.              write(' Expansion ROM of ');
  1536.              if romsize>1000 then write(romsize/1024:4:0,'Mb') else write(romsize,'Kb');
  1537.              writeln(' decoded by this card');
  1538.            end;
  1539.          end;
  1540.        end;
  1541.  
  1542.  
  1543.  
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550. { PCI Bridges info starts here }
  1551.  
  1552. { type 1 header only - List bridge info }
  1553.  
  1554.        if not summary then
  1555.        begin
  1556.  
  1557.        if infotbl[$e] and $7f=1 then
  1558.        begin
  1559.           writeln(' PCI Bridge Information:');
  1560.          write('   Primary Bus Number ',infotbl[$18],', Secondary Bus Number ',infotbl[$19]);
  1561.          writeln(', Subordinate Bus Number ',infotbl[$1a]);
  1562.  
  1563. { seconday bus command }
  1564.          first:=true;
  1565.          write('   Secondary Bus Command ',wrhexw(infotbl[$3f] shl 8 + infotbl[$3e]),'h ');
  1566.          write('(');
  1567.          if infotbl[$3e] and 1=1 then printstatus('parity detection');
  1568.          if infotbl[$3e] and 4=4 then printstatus('ISA mapping');
  1569.          if infotbl[$3e] and 8=8 then printstatus('VGA mapping');
  1570.          if infotbl[$3e] and 32=32 then printstatus('master abort mode');
  1571.          if infotbl[$3e] and 64=64 then printstatus('secondary bus is in RESET');
  1572.          if infotbl[$3e] and 128=128 then printstatus('back-to-back transactions');
  1573.          writeln(')');
  1574.  
  1575.  
  1576. { secondary bus status }
  1577.         write('   Secondary Bus Status ',wrhexw(infotbl[$1f] shl 8+infotbl[$1e]),'h');
  1578.         if (infotbl[$1e]<>0) or (infotbl[$1f]<>0) then
  1579.         begin
  1580.           first:=true;
  1581.           write(' (');
  1582.           if infotbl[$1e] and 32=32 then printstatus('Supports 66MHz');
  1583.           if infotbl[$1e] and 128=128 then printstatus('Supports Back-To-Back Trans.');
  1584.           if infotbl[$1f] and 1=1 then printstatus('Data parity Error Detected');
  1585.           if infotbl[$1f] and 8=8 then printstatus('Signalled Target Abort');
  1586.           if infotbl[$1f] and 16=16 then printstatus('Received Target Abort');
  1587.           if infotbl[$1f] and 32=32 then printstatus('Received Master Abort');
  1588.           if infotbl[$1f] and 64=64 then printstatus('Received System Error');
  1589.           if infotbl[$1f] and 128=128 then printstatus('Detected Parity Error');
  1590.           case ((infotbl[$1f] and 6) shr 1) of
  1591.         0 : printstatus('Fast Timing');
  1592.         1 : printstatus('Medium Timing');
  1593.         2 : printstatus('Slow Timing');
  1594.         3 : printstatus('Unknown Timing');
  1595.           end;
  1596.           write(')');
  1597.         end;
  1598.         writeln;
  1599.  
  1600. { latency }
  1601.         writeln('   Secondary Bus Latency ',wrhex(infotbl[$1b]),'h');
  1602.  
  1603. { I/O port range passed by bridge }
  1604.          if (infotbl[$1c]<>0) or (infotbl[$1d]<>0) then
  1605.          begin
  1606.            write('   I/O Port Range Passed to Secondary Bus : ');
  1607.  
  1608. { 16-bit I/O }
  1609.            if infotbl[$1c] and $f=0 then
  1610.            begin
  1611.          if infotbl[$1d]<infotbl[$1c] then writeln('None') else
  1612.          begin
  1613.            write(wrhexb(infotbl[$1c] shr 4),'000h to ');
  1614.            writeln(wrhexb(infotbl[$1d] shr 4),'FFFh (16-bit)');
  1615.          end;
  1616.            end;
  1617. { 32-bit I/O }
  1618.            if infotbl[$1c] and $f=1 then
  1619.            begin
  1620.          if (infotbl[$33] shl 8 + infotbl[$32]) < (infotbl[$31] shl 8 + infotbl[$30]) then writeln('None') else
  1621.          begin
  1622.            write(wrhexw(infotbl[$31] shl 8 + infotbl[$30]),wrhexb(infotbl[$1c] shr 4),'000h to ');
  1623.            writeln(wrhexw(infotbl[$33] shl 8 + infotbl[$32]),wrhexb(infotbl[$1d] shr 4),'FFFh (32-bit)');
  1624.          end;
  1625.            end;
  1626.          end;
  1627.  
  1628.  
  1629.  
  1630. { memory range passed by bridge }
  1631.          write('   Memory   Range Passed to Secondary Bus : ');
  1632.          mb:=((infotbl[$21] shl 8) + infotbl[$20]) and $fff0;
  1633.          ml:=((infotbl[$23] shl 8) + infotbl[$22]) or $000f;
  1634.          if ml<mb then writeln('None') else writeln(wrhexw(mb),'0000h to ',wrhexw(ml),'FFFFh');
  1635.  
  1636.  
  1637. { optional: prefectchable memory range passed by bridge }
  1638.          if ((infotbl[$27] shl 8 + infotbl[$26])<>0) or ((infotbl[$25] shl 8 + infotbl[$24])<>0) then
  1639.          begin
  1640.            write('   Prefectchable Memory Range Passed to Secondary Bus : ');
  1641.            mb:=((infotbl[$25] shl 8) + infotbl[$24]) and $fff0;
  1642.            ml:=((infotbl[$27] shl 8) + infotbl[$26]) or $000f;
  1643.                if ml<mb then writeln('None') else
  1644.                begin
  1645. { 64 bit base reg? }               
  1646.          if infotbl[$24] and $0f=1 then
  1647.            write(wrhexw(infotbl[$2b] shl 8 + infotbl[$2a]),wrhexw(infotbl[$29] shl 8 + infotbl[$28]));
  1648.              write(wrhexw(mb),'0000h to ');
  1649. { 64 bits limit reg? }           
  1650.          if infotbl[$26] and $0f=1 then
  1651.            write(wrhexw(infotbl[$2f] shl 8 + infotbl[$2e]),wrhexw(infotbl[$2d] shl 8 + infotbl[$2c]));
  1652.              writeln(wrhexw(ml),'FFFFh');
  1653.            end;
  1654.          end;
  1655.  
  1656.  
  1657.        end;
  1658.        end;
  1659.  
  1660.  
  1661.  
  1662.  
  1663.  
  1664. { type 2 header only - List bus numbers etc }
  1665.  
  1666.        if not summary then
  1667.        begin
  1668.          if infotbl[$e] and $7f=2 then
  1669.          begin
  1670.            write(' PCI bus number ',infotbl[$18],', CardBus bus number ',infotbl[$19]);
  1671.            writeln(', Subordinate bus number ',infotbl[$1a]);
  1672.            writeln(' CardBus latency ',wrhex(infotbl[$1b]),'h');
  1673.          end;
  1674.        end;
  1675.  
  1676.  
  1677. { explore the capabilities list, if present }
  1678.        if not summary then
  1679.        begin
  1680.          if (infotbl[6] and $10=$10) then docapdecode;
  1681.        end;
  1682.  
  1683.  
  1684. { do a hex-dump, if requested }
  1685.        if dumpregs then
  1686.        begin
  1687.          writeln;
  1688.          writeln(' Hex-Dump of device configuration space follows:');
  1689.          write('  0000  ');
  1690.          for i:=0 to $ff do
  1691.          begin
  1692.            if (i>0) and (i mod 16=0) then
  1693.            begin
  1694.          write('   ');
  1695.          for j:=i-16 to i-1 do if ord(infotbl[j])<32 then write('.') else write(chr(infotbl[j]));
  1696.          writeln;
  1697.          write('  ',wrhexw(i),'  ');
  1698.            end;
  1699.            write(wrhex(infotbl[i]),' ');
  1700.          end;
  1701.          write('   ');
  1702.          for j:=240 to 255 do if ord(infotbl[j])<32 then write('.') else write(chr(infotbl[j]));
  1703.          writeln;
  1704.        end;
  1705.  
  1706.     writeln;
  1707.   end;
  1708. end;
  1709.  
  1710.  
  1711.  
  1712.  
  1713.  
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722.  
  1723.  
  1724.  
  1725. begin
  1726.   agpbusnum:=$ff;
  1727.   businfo:=false;
  1728.   dorouting:=true;
  1729.   dopcirouting:=false;
  1730.   dumpregs:=false;
  1731.   usebios:=true;
  1732.   summary:=false;
  1733.   installermode:=false;
  1734.   cardptr:=0;
  1735.  
  1736. { the following hack permits MS-DOS display output redirection to work }
  1737.   if ioredirected then
  1738.   begin
  1739.     writeln('Craig Hart''s PCI+AGP bus sniffer, version ',revision,', freeware made in 1996-2001.');
  1740.     assign(output,'');
  1741.     rewrite(output);
  1742.   end else
  1743. { code to do page pausing }
  1744.   begin
  1745.     ClrScr;
  1746.     linecounter:=0;
  1747.     with TextRec(Output) do
  1748.     begin
  1749.       org_output:=FlushFunc;
  1750.       FlushFunc:=@page_output_FlushFunc;
  1751.     end;
  1752.   end;
  1753.  
  1754.  
  1755.  
  1756.   for i:=0 to 15 do irqmap[i]:=0;
  1757.   failed:=true;
  1758.  
  1759.  
  1760.  
  1761.  
  1762.   if paramcount>0 then
  1763.   begin
  1764.     for i:=1 to paramcount do
  1765.     begin
  1766.       cmdstr:=paramstr(i);
  1767.       for j:=1 to length(cmdstr) do cmdstr[j]:=upcase(cmdstr[j]);
  1768.       if (cmdstr='/H') or (cmdstr='-H') then usebios:=false;
  1769.       if (cmdstr='/D') or (cmdstr='-D') then dumpregs:=true;
  1770.       if (cmdstr='/T') or (cmdstr='-T') then dorouting:=false;
  1771.       if (cmdstr='/P') or (cmdstr='-P') then dopcirouting:=true;
  1772.       if (cmdstr='/B') or (cmdstr='-B') then businfo:=true;
  1773.       if (cmdstr='/S') or (cmdstr='-S') then summary:=true;
  1774.       if (cmdstr='/I') or (cmdstr='-I') then installermode:=true;
  1775.       if (cmdstr='?') or (cmdstr='/?') or (cmdstr='-?') then
  1776.       begin
  1777.     textmode(co80);
  1778.     writeln(' Help for PCI  (Version ',revision,')');
  1779.     textcolor(8);
  1780.     writeln('───────────────────────────────');
  1781.     textcolor(7);
  1782.     writeln;
  1783.     writeln('Usage: PCI [-H] [-D] [-S] [-T] [-B] [-P] [-?]   [] indicates optional parameter');
  1784.     writeln;
  1785.     writeln;
  1786.     writeln('-H : Use direct hardware access (instead of the BIOS) to retrieve PCI Info');
  1787.     writeln('     May be required for accurate reporting on Intel 430FX chipset+Award BIOS');
  1788.     writeln('-D : Do a hex-dump of each device''s entire configuration space');
  1789.     writeln('-S : Create a brief, summary report only; only devices and IRQs listed');
  1790.     writeln('-T : Disable the test ROM IRQ Routing Table function');
  1791.     writeln('-B : Enable display of the Bus, Device & Function information');
  1792.     writeln('-P : Enable display of PCI slot routing data');
  1793.     writeln('-I : Installer mode: produce raw data dump (for use with auto-setup programs)');
  1794.     writeln('-? : Displays this help screen!');
  1795.     writeln;
  1796.     writeln('PCI Supports generating reports to a file or printer using MS-DOS pipes; i.e.');
  1797.     writeln;
  1798.     writeln('  PCI -D > REPORT.TXT  (Save report to file),  PCI > LPT1:  (Print report)');
  1799.     writeln;
  1800.     writeln('PCI is written by Craig Hart, and is released as freeware, with no restictions');
  1801.     write('on use or copying. Visit ');
  1802.     textcolor(11);
  1803.     write('http://members.datafast.net.au/chart ');
  1804.     textcolor(7);
  1805.     writeln('for updates to');
  1806.     writeln('the program and the PCI Database file PCIDEVS.TXT');
  1807.     halt(10);
  1808.       end;
  1809.     end;
  1810.   end;
  1811.  
  1812.  
  1813. { fix up conflicting commandline switches }
  1814.  
  1815.   if installermode then
  1816.   begin
  1817.     dorouting:=false;
  1818.     dopcirouting:=false;
  1819.     dumpregs:=false;
  1820.     businfo:=false;
  1821.     summary:=false;
  1822.   end;
  1823.  
  1824.   if summary then
  1825.   begin
  1826.     dumpregs:=false;
  1827.     dopcirouting:=false;
  1828.     dorouting:=false;
  1829.   end;
  1830.  
  1831.  
  1832.  
  1833.  
  1834.   if not installermode then
  1835.   begin
  1836.     assign(f,'pcidevs.txt');
  1837.     {$i-}
  1838.     reset(f);
  1839.     if ioresult<>0 then
  1840.     begin
  1841.       writeln('PCI Halted:');
  1842.       writeln;
  1843.       writeln('Sorry, I cannot locate my PCIDEVS.TXT datafile!!!');
  1844.       writeln('I expect it to be in the CURRENT directory, so don''t run me from a path!!!');
  1845.       halt(10);
  1846.     end;
  1847.     close(f);
  1848.     {$i+}
  1849.   end;
  1850.  
  1851.  
  1852.  
  1853.   if test8086<2 then
  1854.   begin
  1855.     writeln('PCI Halted:');
  1856.     writeln;
  1857.     writeln('The PC Must be at least a 386 to possibly have a PCI or AGP bus!');
  1858.     halt(1);
  1859.   end;
  1860.  
  1861. { Look for PCI BIOS }
  1862.  
  1863.   asm
  1864.     mov ax,$b101
  1865.     int $1a
  1866.     jc @exit
  1867.  
  1868. { check signature bytes OK }
  1869.     cmp dx,$4350
  1870.     jne @exit
  1871.  
  1872. { check no error code returned > AH=00=Success }
  1873.     cmp ah,0
  1874.     jne @exit
  1875.  
  1876.     mov PCIchar,al
  1877.     mov PCI_hibus,cl
  1878.     mov PCIverlo,bl
  1879.     mov PCIverhi,bh
  1880.     mov failed,false
  1881.  
  1882.   @exit:
  1883.   end;
  1884.  
  1885.   if failed then
  1886.   begin
  1887.     writeln('PCI Halted:');
  1888.     writeln;
  1889.     writeln('No PCI BIOS was detected! (NB: I don''t work under Windows NT/2000/XP/2003 etc!)');
  1890.     writeln;
  1891.     writeln('For PCI reports under Win NT-era OS''s such as NT/2K/XP/2K3, use PCI32.EXE');
  1892.     writeln('which is available from the same website as this program (See PCI /? for the');
  1893.     writeln('website address.)');
  1894.     writeln;
  1895.     halt(2);
  1896.   end;
  1897.  
  1898.  
  1899.  
  1900. { OK, we have PCI... do our stuff.. }
  1901.  
  1902.  
  1903.   begin
  1904.     if not installermode then
  1905.     begin
  1906.  
  1907.       if not ioredirected then textmode(co80+font8x8);
  1908.       writeln(' Craig Hart''s PCI+AGP bus sniffer, version ',revision,', freeware made in 1996-2004a.');
  1909.       writeln;
  1910.       write('PCI BIOS Version ',PCIverhi,'.',wrhex(PCIverlo),' found!');
  1911.  
  1912.       if summary then writeln('                                  (Summary Report)') else
  1913.  
  1914.       writeln;
  1915.       writeln('Number of PCI Busses : ',PCI_hibus+1);
  1916.       write('PCI Characteristics  : ');
  1917.       if PCIchar and 1=1 then write('Config Mechanism 1 ') else usebios:=true; { must use BIOS if no cfg mech 1 supported }
  1918.       if PCIchar and 2=2 then write('Config Mechanism 2 ');
  1919.       if PCIchar and 16=16 then write('Special Cycle Mechanism 1 ');
  1920.       if PCIchar and 32=32 then write('Special Cycle Mechanism 2 ');
  1921.       writeln;
  1922.       writeln;
  1923.       write('Searching for PCI Devices using ');
  1924.       if usebios then writeln('the System BIOS') else writeln('Configuration Mechanism 1');
  1925.       writeln;
  1926.     end;
  1927.  
  1928.  
  1929.  
  1930.  
  1931.     for bus:=0 to pci_hibus do        { fix bugs for 440LX chipset, 2 PCI buses, AGP=1 bus! }
  1932.     begin
  1933.       for deviceid:=0 to $1f do
  1934.       begin
  1935.         func:=0;
  1936.         repeat
  1937.       index:=0;
  1938.       repeat
  1939.         if usebios then info:=lookup_bios(deviceid,func,bus,index) else info:=lookup_hw(deviceid,func,bus,index);
  1940.         infotbl[index]:=info;
  1941.         inc(index);
  1942. {don't try to read cfg-space of non-existant devices: hangs some chipsets!}
  1943.         if index=2 then if (infotbl[0]=$ff) and (infotbl[1]=$ff) then index:=$100;
  1944. {don't read past $3f if in short-info modes; avoids crashing on intolerant hardware!}
  1945.         if index=$40 then if installermode or summary then index:=$100;
  1946.       until (index=$100);
  1947.       if (infotbl[0]<>$ff) or (infotbl[1]<>$ff) then
  1948.       begin
  1949. { remember CardBus stuff for later; skip if far bus=0 (i.e. unconfigured) }
  1950.         if (infotbl[$e] and $7f=2) and (infotbl[$19]<>0) then
  1951.         begin
  1952.           cardbus[cardptr+1]:=infotbl[$19];
  1953.           cardptr:=cardptr+1;
  1954.         end;
  1955.         showallinfo;
  1956.       end;
  1957.       inc(func);
  1958. { if func 0 = invalid device, don't test for presence of func 1->7 at all. [$e] isn't valid if [0] and [1] aren't!! }
  1959.           if (func=1) and (infotbl[0]=$ff) and (infotbl[1]=$ff) then func:=8;
  1960. { If not multi-device device, then don't test for func 1-7 as some cards
  1961. incorrectly answer back on all 8 function numbers!!! S3 trio64, for example - stupid!  }    
  1962.           if (func=1) and (infotbl[$e] and $80=0) then func:=8;
  1963.         until func=8; {func }
  1964.       end; {dev }
  1965.     end; { bus }
  1966.  
  1967.  
  1968.  
  1969. { now scan any CardBus busses that weren't included in the BIOS bus count }
  1970.  
  1971.  
  1972.  
  1973.     if cardptr>0 then
  1974.     begin
  1975.       for cbu:=1 to cardptr do        { scan all cardbus busses }
  1976.       begin
  1977.     bus:=cardbus[cbu];
  1978.     if bus>pci_hibus then        { but only those the BIOS hasn't already had us scan }
  1979.     begin
  1980.       for deviceid:=0 to $1f do
  1981.       begin
  1982.         func:=0;
  1983.         repeat
  1984.           index:=0;
  1985.           repeat
  1986.                 if usebios then info:=lookup_bios(deviceid,func,bus,index) else info:=lookup_hw(deviceid,func,bus,index);
  1987.         infotbl[index]:=info;
  1988.         inc(index);
  1989.         if index=2 then if (infotbl[0]=$ff) and (infotbl[1]=$ff) then index:=$100;
  1990.         if index=$40 then if installermode or summary then index:=$100;
  1991.           until (index=$100);
  1992.           if (infotbl[0]<>$ff) or (infotbl[1]<>$ff) then showallinfo;
  1993.           inc(func);
  1994.           if (func=1) and (infotbl[0]=$ff) and (infotbl[1]=$ff) then func:=8;
  1995.           if (func=1) and (infotbl[$e] and $80=0) then func:=8;
  1996.         until func=8;
  1997.       end;
  1998.     end;
  1999.       end;
  2000.     end;
  2001.  
  2002. {
  2003.   The following is an experiment with "Get IRQ Routing Info" BIOS function:
  2004.   the avid coder is free to un-comment the code and try it out: I couldn't
  2005.   make much sense out of the information returned myself!
  2006. }
  2007.  
  2008.  
  2009.  
  2010.     if dopcirouting then
  2011.     begin
  2012.  
  2013.  
  2014.       writeln;
  2015.       writeln('PCI slot IRQ mapping information');
  2016.       irqbuff[0]:=lo(1024);
  2017.       irqbuff[1]:=hi(1024);
  2018.  
  2019.       irqbuff[2]:=lo(ofs(irqbuff)+2);
  2020.       irqbuff[3]:=hi(ofs(irqbuff)+2);
  2021.       irqbuff[4]:=lo(seg(irqbuff));
  2022.       irqbuff[5]:=hi(seg(irqbuff));
  2023.  
  2024.  
  2025.       failed:=true;
  2026.  
  2027.  
  2028.       asm
  2029.     push ds
  2030.  
  2031.     mov bx,0
  2032.     mov ax,seg irqbuff
  2033.     mov es,ax
  2034.     mov di,offset irqbuff
  2035.     mov ax,0f000h
  2036.     mov ds,ax
  2037.     mov ax,0b10eh
  2038.  
  2039.     int $1a
  2040.     pop ds
  2041.  
  2042.     mov cx,word ptr es:[di]
  2043.  
  2044.     cmp ah,0
  2045.     jne @exit
  2046.  
  2047.  
  2048.     mov conmap,bx
  2049.     mov len,cx
  2050.     mov failed,false
  2051.  
  2052.       @exit:
  2053.       end;
  2054.  
  2055.  
  2056.       if not failed then
  2057.       begin
  2058.     textcolor(10);
  2059.     writeln(' PCI slot mapping information read successfully');
  2060.     textcolor(7);
  2061.     writeln;
  2062.  
  2063.  
  2064. { hex-dump table }
  2065.     if dumpregs then dohexdump;
  2066.  
  2067. {}
  2068.     writeln(' PCI slot IRQ availability listing');
  2069.     writeln;
  2070.     for i:=0 to (len shr 4)-1 do
  2071.     begin
  2072.       writeln('  PCI Bus ',irqbuff[2+(i*16)],', Device ',irqbuff[3+(i*16)] shr 3,', Slot ',wrhex(irqbuff[16+(i*16)]));
  2073.       listmap(irqbuff[6+(i*16)] shl 8 + irqbuff[5+(i*16)],'   INTA# can be connected to IRQs ');
  2074.       listmap(irqbuff[9+(i*16)] shl 8 + irqbuff[8+(i*16)],'   INTB# can be connected to IRQs ');
  2075.       listmap(irqbuff[12+(i*16)] shl 8 + irqbuff[11+(i*16)],'   INTC# can be connected to IRQs ');
  2076.       listmap(irqbuff[15+(i*16)] shl 8 + irqbuff[14+(i*16)],'   INTD# can be connected to IRQs ');
  2077.       writeln;
  2078.     end;
  2079.     writeln;
  2080.  
  2081.  
  2082. {}
  2083.     writeln(' PCI slot INTx to IRQ-router mappings');
  2084.     writeln;
  2085.     writeln('  SLOT BUS DEV  INTA INTB INTC INTD');
  2086.     for i:=0 to (len shr 4)-1 do
  2087.     begin
  2088.       write('   ',wrhex(irqbuff[16+(i*16)]),'  ',irqbuff[2+(i*16)]:2,'  ',irqbuff[3+(i*16)] shr 3:2);
  2089. {      write('   ',irqbuff[3+(i*16)] and 3);}
  2090.       write('    ',wrhex(irqbuff[4+(i*16)]),'   ',wrhex(irqbuff[7+(i*16)]),'   ',
  2091.         wrhex(irqbuff[10+(i*16)]),'   ',wrhex(irqbuff[13+(i*16)]),'  ');
  2092.  
  2093.       if usebios then
  2094.       begin
  2095.         infotbl[0]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],0);
  2096.         infotbl[1]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],1);
  2097.         infotbl[2]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],2);
  2098.         infotbl[3]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],3);
  2099.         infotbl[4]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],4);
  2100.         infotbl[5]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],5);
  2101.         infotbl[6]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],6);
  2102.         infotbl[7]:=lookup_bios(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],7);
  2103.       end else
  2104.       begin
  2105.         infotbl[0]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],0);
  2106.         infotbl[1]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],1);
  2107.         infotbl[2]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],2);
  2108.         infotbl[3]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],3);
  2109.         infotbl[4]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],4);
  2110.         infotbl[5]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],5);
  2111.         infotbl[6]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],6);
  2112.         infotbl[7]:=lookup_hw(irqbuff[3+(i*16)] shr 3,irqbuff[3+(i*16)] and 3,irqbuff[2+(i*16)],7);
  2113.       end;
  2114.  
  2115.       cmpstr:=wrhexw(infotbl[1] shl 8+infotbl[0]);
  2116.       if cmpstr<>'FFFF' then
  2117.       begin
  2118.         lookupven(true);
  2119.         cmpstr:=wrhexw(infotbl[3] shl 8+infotbl[2]);
  2120.         lookupdev;
  2121.       end else write('No Device Detected');
  2122.  
  2123.  
  2124.  
  2125.  
  2126.       writeln;
  2127.     end;
  2128.     writeln;
  2129.  
  2130.  
  2131. {}
  2132.     listmap(conmap,' IRQ''s dedicated to PCI : ');
  2133.  
  2134.       end else
  2135.       begin
  2136.     textcolor(12);
  2137.     writeln(' Unable to read slot mapping information from PCI BIOS!');
  2138.     textcolor(7);
  2139.       end;
  2140.       writeln;
  2141.     end;
  2142.  
  2143.  
  2144.  
  2145.  
  2146.  
  2147. { BIOS IRQ Routing table tests }
  2148.  
  2149.     if dorouting then
  2150.     begin
  2151.       showroutinginfo;
  2152.     end;
  2153.  
  2154.  
  2155.  
  2156.  
  2157.  
  2158. { final summarial IRQ info }
  2159.  
  2160.     if not installermode then
  2161.     begin
  2162.       writeln;
  2163.       write('IRQ Summary: ');
  2164.       failed:=true;
  2165.       disp:=0;
  2166.       for i:=0 to 15 do if irqmap[i]>0 then inc(disp); { count IRQs}
  2167.       for i:=0 to 15 do if irqmap[i]>0 then
  2168.       begin
  2169.     if failed then
  2170.     begin
  2171.       if disp=1 then write('IRQ ') else write('IRQs ');
  2172.     end else write(',');
  2173.     write(i);
  2174.     failed:=false;
  2175.       end;
  2176.       if failed then writeln('No IRQ''s are used by PCI Devices!') else
  2177.       begin
  2178.     if disp=1 then write(' is') else write(' are');
  2179.     writeln(' used by PCI devices');
  2180.       end;
  2181.  
  2182.       write('Shared IRQs: ');
  2183.       failed:=true;
  2184.       for i:=0 to 15 do if irqmap[i]>1 then
  2185.       begin
  2186.     if not failed then write('             ');
  2187.     writeln('IRQ ',i,' is shared by ',irqmap[i],' PCI Devices');
  2188.     failed:=false;
  2189.       end;
  2190.       if failed then writeln('There are no shared PCI IRQs');
  2191.     end;
  2192.   end;
  2193. end.
  2194.  
  2195.